package com.thingsgrid.device.service.impl;

import com.mongodb.BasicDBObject;
import com.thingsgrid.device.base.AbstractDevice;
import com.thingsgrid.device.dto.DeviceDTO;
import com.thingsgrid.device.dto.TopicDTO;
import com.thingsgrid.device.entity.*;
import com.thingsgrid.device.feign.IProductClient;
import com.thingsgrid.device.mapper.DeviceMapper;
import com.thingsgrid.device.service.IDeviceService;
import org.apache.commons.lang3.StringUtils;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.api.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.LookupOperation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.sql.Array;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

@ComponentScan("com.springblade.product.feign")

@Service
public class DeviceServiceImpl extends AbstractDevice implements IDeviceService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private IProductClient client;
    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public void addSlaveDevice(String slaveId, String deviceId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(deviceId));
        DeviceItem deviceItem = new DeviceItem();
        deviceItem.setDeviceId(slaveId);
        Update update = new Update();
        update.addToSet("slaveDeviceIdList", deviceItem);
        mongoTemplate.upsert(query, update, Device.class);
    }

    /**
     *说明：删除子设备
     *@author lilongfei
     *@since 2019/9/26 13:58
     */
    @Override
    public long removeSlaveDevice(String slaveId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("device_id").is(slaveId));
        Update update = new Update();
        update.set("parent_device_id", "");
        return mongoTemplate.updateFirst(query, update, Device.class).getModifiedCount();
    }


    //	@Override
//	public List<Device> listSlaveDevices(Integer pageIndex, Integer pageSize,String deviceId) {
//		Query query = new Query();
//		Criteria criteria = new Criteria();
//		query.addCriteria(criteria.where("_id").is(deviceId));
//		Device one = mongoTemplate.findOne(query,Device.class);
//		List<DeviceItem> slaveDeviceItems = one.getSlaveDeviceIdList();
//
//		Query query1 = new Query();
//		Criteria criteria1 = new Criteria();
//		query1.addCriteria(criteria1.where("_id").in(slaveDeviceItems));
//				//Criteria criteria = new Criteria();
//		Pageable pageable = new PageRequest(pageIndex-1, pageSize);
//		query1.with(pageable);
//		return mongoTemplate.find(query1,Device.class);
//	}
    /**
     *说明：查询子设备列表
     *@author lilongfei
     *@since 2019/9/26 13:55
     */
    @Override
    public Map<String,Object> listSlaveDevices(String deviceId, Integer currentPage, Integer size) {
        if (currentPage <= 0) {
            currentPage = 1;
        }
        //查询子设备列表
        LookupOperation leftJoinProduct = LookupOperation.newLookup()
                .from("product")
                .localField("product_id")
                .foreignField("product_id")
                .as("productInfo");

        //查询条件
        MatchOperation matchOperation = new MatchOperation(Criteria.where("parent_device_id").is(deviceId));
        //筛选查询结果
        ProjectionOperation project = Aggregation.project("device_id","device_name", "productInfo.product_name", "device_shadow", "productInfo.product_point_type", "describe", "create_time");
        Aggregation aggregation = Aggregation.newAggregation(leftJoinProduct, matchOperation, project
                , Aggregation.skip((currentPage - 1) * size), Aggregation.limit(size));
        Aggregation countAggregation = Aggregation.newAggregation(leftJoinProduct, matchOperation, project
                , Aggregation.skip((currentPage - 1) * size), Aggregation.limit(size));
        List<DeviceDTO> results = mongoTemplate.aggregate(countAggregation,"device",DeviceDTO.class).getMappedResults();
        List<DeviceDTO> dtoList = mongoTemplate.aggregate(aggregation, "device", DeviceDTO.class).getMappedResults();
        //设置参数
        if (dtoList.size() > 0) {
            for (DeviceDTO deviceDTO : dtoList) {
                System.out.println(deviceDTO);
                if(null!=deviceDTO.getDeviceShadow()){
                    if ("ON".equals(deviceDTO.getDeviceShadow().getState().get("reported").get("online"))) {
                        deviceDTO.setOnlineState("开机");
                    } else {
                        deviceDTO.setOnlineState("关机");
                    }
                }
                if(null!=deviceDTO.getProductPointType()){
                    if ("0".equals(deviceDTO.getProductPointType())) {
                        deviceDTO.setProductPointType("设备");
                    } else {
                        deviceDTO.setProductPointType("网关");
                    }
                }
            }
        }
        Map<String,Object> map = new HashMap<>();
        map.put("deviceList",dtoList);
        map.put("count",results.size());
        return map;
    }

    /**
     * 说明：查询设备影子列表
     *
     * @author lilongfei
     * @since 2019/9/20 10:37
     */
    @Override
    public List<Shadow> listDeviceShadow(String deviceId) {
        List<Shadow> shadowList = new ArrayList<>();
        //连接产品表
        LookupOperation leftJoinProduct = LookupOperation.newLookup()
                .from("product")
                .localField("product_id")
                .foreignField("product_id")
                .as("productList");
        //过滤条件
        MatchOperation matchOperation = new MatchOperation(Criteria.where("device_id").is(deviceId));
        //过滤字段
        ProjectionOperation projectionOperation = Aggregation.project("productList.product_attribute", "device_shadow");
        Aggregation aggregation = Aggregation.newAggregation(leftJoinProduct, matchOperation, projectionOperation);
        DeviceDTO deviceDTO = mongoTemplate.aggregate(aggregation, "device", DeviceDTO.class).getMappedResults().get(0);
        //封装属性值
        for (Map.Entry<String, String> entry : deviceDTO.getDeviceShadow().getState().get("reported").entrySet()) {
            for (PhysicalAttribute physicalAttribute : deviceDTO.getPhysicalAttributeList()) {
                if (entry.getKey().equals(physicalAttribute.getTagName())) {
                    Shadow shadow = new Shadow();
                    shadow.setAttibuteName(entry.getKey());
                    shadow.setAttibuteNameShowing(physicalAttribute.getPropertyName());
                    shadow.setAttibuteType(physicalAttribute.getDataType());
                    shadow.setAttibuteUnit(physicalAttribute.getUnit());
                    shadow.setAttibuteCurrentValue(entry.getValue());
                    for (Map.Entry<String, String> expect : deviceDTO.getDeviceShadow().getState().get("desired").entrySet()) {
                        if (expect.getKey().equals(entry.getKey())) {
                            shadow.setAttibuteExpectedValue(expect.getValue());
                            break;
                        }
                    }
                    shadowList.add(shadow);
                }
            }
        }
        return shadowList;
    }

    /**
     * 添加设备
     *
     * @param device 设备信息
     */
    @Override
    public Device saveDevice(Device device) {
        String str = UUID.randomUUID().toString().replace("-", "").substring(0, 12);
        String deviceId = UUID.randomUUID().toString().replace("-", "").substring(0, 12);
        device.setDeviceSecret(str);
        device.setDeviceId(deviceId);
        DeviceShadow deviceShadow = new DeviceShadow();
        Map<String,Map<String,String>> deviceState = new HashMap<>();
        Map<String,String> deviceStateInfo = new HashMap<>();
        deviceStateInfo.put("online","OFF");
        deviceState.put("report",deviceStateInfo);
        deviceShadow.setState(deviceState);
        device.setDeviceShadow(deviceShadow);
        device.setIsPublish("0");
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = df.format(new Date());
        device.setCreateTime(format);
        Product product = this.getProductById(device.getProductId());
        if (product != null) {
            device.setProductPointType(Integer.toString(product.getProductPointType()));
        }
        //新增设备
        Device newDevice = mongoTemplate.save(device);
        //新增设备默认配置
        DefaultConfig defaultConfig = new DefaultConfig(newDevice.getDeviceName(), newDevice.getDeviceId(), newDevice.getProductId(),
                newDevice.getDeviceFirm(), newDevice.getDeviceType(), newDevice.getFirmwareVersion(), newDevice.getOperateUnit(), newDevice.getMaintainPerson(),
                newDevice.getMaintainPersonPhone(), newDevice.getProvince(), newDevice.getCity(), newDevice.getRegion(), newDevice.getLongitude(), newDevice.getDimension()
                , newDevice.getIpAddress(), newDevice.getDescribe(), newDevice.getCreateTime());
        mongoTemplate.save(defaultConfig);
        return newDevice;
    }

    /**
     * 删除设备
     *
     * @param deviceId 设备id
     */
    @Override
    public long removeDevice(String deviceId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("device_id").is(deviceId));
        long result = mongoTemplate.remove(query, Device.class).getDeletedCount();
        return result;
    }

    /**
     * 更新设备
     *
     * @param device 设备信息
     */
    @Override
    public void updateDevice(Device device) {
        Query query = new Query();
        query.addCriteria(Criteria.where("deviceId").is(device.getDeviceId()));
        Update update = new Update();
        update.set("deviceName", device.getDeviceName());
        update.set("deviceFirm", device.getDeviceFirm());
        update.set("deviceType", device.getDeviceType());
        update.set("firmwareVersion", device.getFirmwareVersion());
        update.set("activeTime", device.getActiveTime());
        update.set("operateUnit", device.getOperateUnit());
        update.set("maintainPerson", device.getMaintainPerson());
        update.set("maintainPersonPhone", device.getMaintainPersonPhone());
        update.set("province", device.getProvince());
        update.set("city", device.getCity());
        update.set("region", device.getRegion());
        update.set("longitude", device.getLongitude());
        update.set("dimension", device.getDimension());
        update.set("ipAddress", device.getIpAddress());
        update.set("stats", device.getStats());
        update.set("founder", device.getFounder());
        update.set("describe", device.getDescribe());
        update.set("startStats", device.getStartStats());
//        update.set("deviceAttribute", device.getDeviceAttribute());
//        update.set("deviceService", device.getDeviceService());
//        update.set("deviceEvent", device.getDeviceEvent());
        mongoTemplate.updateFirst(query, update, Device.class);
    }

    /**
     * 通过id查设备
     *
     * @param deviceId 设备Id
     * @return
     */
    @Override
    public Map<String, Object> findDeviceById(String deviceId) {
        Map<String, Object> deviceObj = new HashMap<>();
        Query query = new Query();
        query.addCriteria(Criteria.where("device_id").is(deviceId));
        Query productQuery = new Query();
        productQuery.addCriteria(Criteria.where("is_publish").is("1"));
        List<Product> productList = mongoTemplate.find(productQuery, Product.class, "product");
        deviceObj.put("provinceList",new Array[10]);
        deviceObj.put("cityList",new Array[10]);
        deviceObj.put("regionList",new Array[10]);
        deviceObj.put("productList", productList);
        List<DeviceDTO> device = mongoTemplate.find(query, DeviceDTO.class,"device");
        System.out.println(device.get(0).getLastOnlineTime());
        if(device.size()>0){
            device = this.controlDeviceList(device);
        }
        deviceObj.put("deviceInfo", device.get(0));
        return deviceObj;
    }

    /**
     * 查找所有
     *
     * @return List<Device>
     */
    @Override
    public List<Device> findAll() {
        return mongoTemplate.findAll(Device.class);
    }

    /**
     * 分页查
     *
     * @param pageIndex 当前页
     * @param pageSize 数量
     * @return
     */
    @Override
    public Map<String, Object> findAll(Integer pageIndex, Integer pageSize) {
        Query query = new Query();
        Pageable pageable = new PageRequest(pageIndex - 1, pageSize);
        query.with(pageable);
        //统计设备总数
        Query countQuery = new Query();
        long deviceCount = mongoTemplate.count(countQuery, "device");
        //统计激活数量
        Query activeQuery = new Query(Criteria.where("active_state"));
        long deviceActiveCount = mongoTemplate.count(activeQuery, "device");
        //统计当前在线数量
        Query onlineQuery = new Query(Criteria.where("device_shadow.state.reported.online").is("ON"));
        long onlineCount = mongoTemplate.count(onlineQuery, "device");
        //查分页查询设备信息
        LookupOperation leftJoinProduct = LookupOperation.newLookup()
                .from("product")
                .localField("product_id")
                .foreignField("product_id")
                .as("productList");
        //过滤字段
        ProjectionOperation projectionOperation = Aggregation.project("productList.product_name","productList.product_id","productList.product_secret", "device_id","device_name","describe","device_shadow","device_secret","productList.product_point_type","create_time","is_publish");
        Aggregation aggregation = Aggregation.newAggregation(leftJoinProduct, projectionOperation,Aggregation.skip((pageIndex-1)*pageSize),Aggregation.limit(pageSize));

        List<DeviceDTO> deviceList = mongoTemplate.aggregate(aggregation, "device", DeviceDTO.class).getMappedResults();
        if (deviceList.size() > 0) {
            deviceList = this.controlDeviceList(deviceList);
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("deviceCount", deviceCount);
        resultMap.put("activeCount", deviceActiveCount);
        resultMap.put("onlineCount", onlineCount);
        resultMap.put("deviceList", deviceList);
        return resultMap;
    }

    /**
     * @param deviceName
     * @param beginTime
     * @param endTime
     * @return
     */
    @Override
    public Map<String,Object> selectByCondition(String deviceName, String productPointType, Timestamp beginTime, Timestamp endTime, Integer isPublish,Integer current,Integer size) {
        //List<Criteria> criteriaList = new ArrayList<>();
        //Criteria[] criteriaArray = {};
        Query query = new Query();
        Pageable pageable = new PageRequest(current - 1, size);
        query.with(pageable);
        //判断产品名是否为空
        if (deviceName != null && !deviceName.trim().equals("")) {
            query.addCriteria(Criteria.where("deviceName").is(deviceName));

        }
        if (productPointType != null && !productPointType.trim().equals("")) {
            query.addCriteria(Criteria.where("product_id").is(productPointType));
        }
        // 判断时间是否为空
        if (beginTime != null && endTime != null) {
             query.addCriteria(Criteria.where("createTime").gte(beginTime).lte(endTime));
        } else {
            // 其中一个为空 分别进行判断
            if (beginTime != null) {
                query.addCriteria(Criteria.where("time").gte(beginTime));
            }
            if (endTime != null) {
                query.addCriteria(Criteria.where("time").gte(endTime));
            }
        }
        // 添加状态为1条件
        if (isPublish != null&&isPublish!=100) {
            query.addCriteria(Criteria.where("isPublish").is(isPublish));
        }
        //获取设备列表
        List<Device> deviceList = mongoTemplate.find(query, Device.class);
        //查询统计
        Pageable pageable1 = new PageRequest(current - 1, 999);
        query.with(pageable1);
        long count = mongoTemplate.count(query,Device.class,"device");
        Map<String,Object> map = new HashMap<>();
        map.put("deviceList",deviceList);
        map.put("count",count);
        return map;

    }

    /**
     * 根据设备id查询topic列表
     *
     * @param deviceId 设备ID
     * @return List<TopicDTO>
     * @author lilongfei
     * @since 2019/9/19 17:42
     */
    @Override
    public Map<String,Object> getTopicListByDeviceId(String deviceId,Integer currentPage,Integer size) {

        //左连接topic类
        LookupOperation leftJoinTopicClass = LookupOperation.newLookup()
                .from("topic")
                .localField("topic_class")
                .foreignField("_id")
                .as("topicClassList");
        //查询条件
        MatchOperation matchOperation = new MatchOperation(Criteria.where("device_id").is(deviceId));
        //过滤查询结果
        ProjectionOperation project = Aggregation.project("_id", "topic_name", "topicClassList.topic_class_name", "topic_content",
                "topic_type", "topic_power", "describe");
        Aggregation aggregation = Aggregation.newAggregation(leftJoinTopicClass, matchOperation, project,Aggregation.skip((currentPage - 1) * size), Aggregation.limit(size));
        List<TopicDTO> topicDTOList = mongoTemplate.aggregate(aggregation, "topic_item", TopicDTO.class).getMappedResults();

        //统计topic数量
        Query queryCount = new Query();
        queryCount.addCriteria(Criteria.where("device_id").is(deviceId));
        Integer count = mongoTemplate.findAll(TopicItem.class,"topic_item").size();

        //封装结果
        Map<String,Object> map = new HashMap<>();
        map.put("topicList",topicDTOList);
        map.put("count",count);
        return map;
    }

    @Override
    public Device findDeviceByDeviceSn(String deviceSn) {
        Query query = new Query();
        query.addCriteria(Criteria.where("deviceSn").is(deviceSn));
        return mongoTemplate.findOne(query, Device.class);
    }

    /**
     *说明：查询可关联的设备列表
     *@author lilongfei
     *@since 2019/9/26 14:47
     */
    @Override
    public Map<String,Object> getRelevanceDeviceList(Integer page,Integer size,String deviceId) {
        Map<String,Object> map = new HashMap<>();
        List<DeviceDTO> deviceList = deviceMapper.getRelevanceDeviceList(page, size,deviceId);
        deviceList = this.controlDeviceList(deviceList);
        long count = deviceMapper.getRelavanceDeviceCount();
        map.put("deviceList",deviceList);
        map.put("count",count);
        return map;
    }


    /**
     *说明：处理设备状态和类型
     *@author lilongfei
     *@since 2019/9/26 15:12
     */
    private List<DeviceDTO> controlDeviceList(List<DeviceDTO> deviceList){
        assert deviceList != null;
        if(deviceList.size()>0){
            for (DeviceDTO deviceDTO : deviceList) {
                System.out.println(deviceDTO.getProductPointType());
                if(null==deviceDTO.getDeviceShadow()){
                    deviceDTO.setOnlineState("关机");
                }else{
                    if ("ON".equals(deviceDTO.getDeviceShadow().getState().get("reported").get("online"))) {
                        deviceDTO.setOnlineState("开机");
                    } else {
                        deviceDTO.setOnlineState("关机");
                    }
                }
                if ("0".equals(deviceDTO.getProductPointType())) {
                    deviceDTO.setProductPointType("设备");
                } else {
                    deviceDTO.setProductPointType("网关");
                }
            }
        }
        return deviceList;
    }

    /**
     *说明：关联设备
     *@author lilongfei
     *@since 2019/9/26 15:25
     */
    @Override
    public long connectDevice(String deviceId, String slaveId) {
        if(deviceId.equals(slaveId)){
            return 0;
        }
        Update update = new Update();
        update.set("parent_device_id",deviceId);
        Query query = new Query(Criteria.where("device_id").is(slaveId));
        return mongoTemplate.updateFirst(query,update,"device").getModifiedCount();
    }

    /**
     *说明：通过产品ID获取设备列表
     *@author lilongfei
     *@since 2019/9/27 14:23
     */
    @Override
    public List<Device> getDeviceListByProductId(String productId) {
        return deviceMapper.getDeviceListByProductId(productId);
    }

    /**
     *说明：设备发布
     *@author lilongfei
     *@since 2019/9/29 14:19
     */
    @Override
    public R devicePublish(String deviceId,String publishState) {
        if(StringUtils.isEmpty(deviceId)||StringUtils.isEmpty(publishState)){
            throw new ServiceException("设备发布参数为空");
        }
        return deviceMapper.devicePublish(deviceId, publishState)>0?R.data("发布成功"): R.fail("发布失败");
    }

}
